﻿using d1Common.Interface;
using d1Project.Modules.Common.doCache.Models;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace d1Project.Modules.Common.doCache.Services
{
    public class doCacheServiceLocal : IDoCache
    {
        public doCacheServiceLocal()
        {
            this.dictCacheData = new Dictionary<string, DoCache>();
            this.lockData = new object();
        }
        private Dictionary<string, DoCache> dictCacheData;

        private string buildUniqueKey(string _group, string _key)
        {
            return _group +"$_$" + _key;
        }
        private object lockData;

        public bool ContainsKey(string group, string key)
        {
            string _uniqueKey = this.buildUniqueKey(group, key);
            bool _exist= this.dictCacheData.ContainsKey(_uniqueKey);
            if (!_exist) return false;
            return this.dictCacheData[_uniqueKey].ExpiredTime >= DateTime.Now;
        }

        public T GetData<T>(string group, string key)
        {
            string _uniqueKey = this.buildUniqueKey(group, key);
            return JsonConvert.DeserializeObject<T>(this.dictCacheData[_uniqueKey].Value);
        }

        public void RemoveData(string group, string key)
        {
            string _uniqueKey = this.buildUniqueKey(group, key);
            lock (this.lockData)
            {
                doCacheDbContext db = new doCacheDbContext();
                try
                {
                    if (this.dictCacheData.ContainsKey(_uniqueKey))
                    {
                        DoCache newDoCache = this.dictCacheData[_uniqueKey];
                        var entity = db.DoCaches.Find(newDoCache.Id);
                        db.DoCaches.Remove(entity);
                        db.SaveChanges();
                        this.dictCacheData.Remove(_uniqueKey);
                    }
                }
                finally
                {
                    db.Dispose();
                }
            }
        }

        public void SetData(string group, string key, object data)
        {
            this.SetData(group, key, data, -1);            
        }

        public void SetData(string group, string key, object data, int cacheTime)
        {
            string _value = JsonConvert.SerializeObject(data);
            string _uniqueKey = this.buildUniqueKey(group, key);
            lock (this.lockData)
            {
                doCacheDbContext db = new doCacheDbContext();
                try
                {
                    if (this.dictCacheData.ContainsKey(_uniqueKey))
                    {
                        DoCache newDoCache = this.dictCacheData[_uniqueKey];
                        newDoCache.Value = _value;
                        if (cacheTime < 0)
                        {
                            newDoCache.ExpiredTime = DateTime.MaxValue;
                        }
                        else
                        {
                            newDoCache.ExpiredTime = DateTime.Now.AddSeconds(cacheTime);
                        }
                        db.Entry(newDoCache).State = System.Data.Entity.EntityState.Modified;
                        db.SaveChanges();
                    }
                    else
                    {
                        DoCache newDoCache = new DoCache();
                        newDoCache.Id = _uniqueKey;
                        newDoCache.Value = _value;
                        if (cacheTime < 0)
                        {
                            newDoCache.ExpiredTime = DateTime.MaxValue;
                        }
                        else
                        {
                            newDoCache.ExpiredTime = DateTime.Now.AddSeconds(cacheTime);
                        }
                        db.DoCaches.Add(newDoCache);
                        db.SaveChanges();
                        this.dictCacheData[_uniqueKey] = newDoCache;
                    }
                }
                finally
                {
                    db.Dispose();
                }
            }
        }

        private bool initilized = false;
        public void InitData()
        {
            if (this.initilized) return;
            this.initilized = true;
            lock (this.lockData)
            {
                List<DoCache> listData = null;
                doCacheDbContext db = new doCacheDbContext();
                try
                {
                    DateTime _dtNow = DateTime.Now;
                    var _expiredResults = db.DoCaches.Where(p => p.ExpiredTime < _dtNow).ToList();
                    if (_expiredResults!=null && _expiredResults.Count > 0)
                    {
                        db.DoCaches.RemoveRange(_expiredResults);
                    }
                    db.SaveChanges();
                    listData = db.DoCaches.ToList<DoCache>();
                }
                finally
                {
                    db.Dispose();
                }
                if (listData == null) return;
                foreach (DoCache _doCache in listData)
                {
                    this.dictCacheData.Add(_doCache.Id, _doCache);
                }
            }
        }
    }
}